package com.ronz.linkedlist;

import com.ronz.linkedlist.util.HeroNode;

import java.util.Scanner;

/**
 * @Description 演示对单链表进行操作：
 *              1. 增加节点到链表中（直接在末尾追加）
 *              2. 按照编号从小到大顺序增加节点到链表中
 *              3. 从链表删除节点
 *              4. 修改链表中节点信息
 *              5. 获取链表节点个数
 * @Author Ronz
 * @Date 2020/12/21 16:12
 * @Version 1.0
 */
public class No1_SingleLinkedList {

    // 头结点中是不存储数据的，因此数据无所谓。只要存储下一个节点的地址即可
    private static final HeroNode headNode = new HeroNode(0, "", "");

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        boolean flag = true;

        while (flag) {
            System.out.println("==========================");
            System.out.println("s\t(show)：\t\t显示所有节点");
            System.out.println("a\t(add)：\t\t\t新增节点");
            System.out.println("o\t(orderAdd)：\t新增节点(根据编号顺序)");
            System.out.println("u\t(update)：\t\t更新节点");
            System.out.println("d\t(delete)：\t\t删除节点");
            System.out.println("c\t(count)：\t\t统计节点个数");
            System.out.println("q\t(quit)：\t\t退出程序");
            System.out.println("==========================");
            String line = input.nextLine();
            char key = line.charAt(0);
            switch (key) {
                case 's':       // 显示所有节点
                    showNodes();
                    break;
                case 'a':       // 新增节点(末尾追加)
                    System.out.println("新增节点->请输入编号(no)：");
                    String no = input.nextLine();
                    System.out.println("新增节点->请输入姓名(name)：");
                    String name = input.nextLine();
                    System.out.println("新增节点->请输入昵称(nickName)：");
                    String nickName = input.nextLine();
                    HeroNode node = new HeroNode(Integer.valueOf(no), name, nickName);
                    insertNode(node);
                    break;
                case 'o':       // 新增节点，按照编号从小到大新增
                    System.out.println("按编号新增节点->请输入编号(no)：");
                    String orderNo = input.nextLine();
                    System.out.println("按编号新增节点->请输入姓名(name)：");
                    String orderName = input.nextLine();
                    System.out.println("按编号新增节点->请输入昵称(nickName)：");
                    String orderNickName = input.nextLine();
                    HeroNode orderNode = new HeroNode(Integer.parseInt(orderNo), orderName, orderNickName);
                    insertNodeByOrder(orderNode);
                    break;
                case 'u':       // 更新节点
                    System.out.println("更新节点—>请输入编号(no)：");
                    int updateNo = Integer.parseInt(input.nextLine());
                    System.out.println("更新节点—>请输入姓名(name)：");
                    String updateName = input.nextLine();
                    System.out.println("更新节点—>请输入昵称(nickName)：");
                    String updateNickName = input.nextLine();
                    HeroNode heroNode = new HeroNode(updateNo, updateName, updateNickName);
                    updateNode(heroNode);
                    break;
                case 'd':      // 删除节点
                    System.out.println("删除节点->请输入编号(no)：");
                    String delNo = input.nextLine();
                    deleteNode(Integer.valueOf(delNo));
                    break;
                case 'c':       // 打印节点个数
                    getSize();
                    break;
                case 'q':      // 退出程序
                    flag = false;
                    break;

                default:
                    break;

            }
        }
    }

    /**
     * @Description 1. 插入节点到链表中（直接在末尾追加）
     */
    private static void insertNode(HeroNode node) {
        // 首先需要获取头结点
        HeroNode tempNode = headNode;
        // 插入节点到链表之中，需要首先遍历链表
        while (true) {
            // 判断有没有到达链表末尾
            if (tempNode.next == null) {
                // 当下一个节点为 null 时，说明到达最后一个元素了
                tempNode.next = node;
                node.next = null;
                System.out.println("++++++++++++ 插入节点成功！");
                break;
            }
            // 没有到达链表末尾，那就后移一个位置
            tempNode = tempNode.next;
        }
    }

    /**
     * @Description 2. 根据编号从小到大顺序插入节点
     */
    public static void insertNodeByOrder(HeroNode node) {
        // 头结点是代码的柱石，不能动
        HeroNode tempNode = headNode;
        while (true) {
            if (tempNode.next == null) {     // 如果到了链表末尾
                tempNode.next = node;
                node.next = null;
                break;
            }
            if (tempNode.next.getNo() > node.getNo()) { // 如果当前节点的下一个节点的编号大于要插入的节点,就插入
                // 先让要插入的节点指向下一个节点
                node.next = tempNode.next;
                // 然后再让当前节点指向要插入的节点
                tempNode.next = node;
                break;
            } else if (tempNode.next.getNo() == node.getNo()) {   // 说明该节点已存在
                System.out.println("!!!!!!!!!! 该节点已存在");
                break;
            }
            // 上述条件都不满足，就继续往后迭代
            tempNode = tempNode.next;
        }
    }


    /**
     * @Description 3. 从链表中删除节点
     * - 删除节点需要考虑如果链表中没有这个节点怎么办？
     */
    private static void deleteNode(int no) {
        // 首先获取到头结点
        HeroNode tempNode = headNode;
        // 遍历节点，找到要删除的节点的前一个节点
        while (true) {
            // 判断当前节点是不是最后一个节点，如果到了末尾还没有找到目标节点，报错警告
            if (tempNode.next == null) {
                System.out.println("!!!!!!!!!! 目标节点不存在！");
                break;
            }

            if (tempNode.next.getNo() == no) {
                // 说明找到了要删除的节点
                // 所谓删除节点，其实就是把要删除的节点的前一个节点的 next 指向要删除的节点的后一个节点
                tempNode.next = tempNode.next.next;
                System.out.println("------------ 更新节点成功！");
                break;
            }
            // 没有找到目标节点，就继续往后移一个位置
            tempNode = tempNode.next;
        }
    }

    /**
     * @return void
     * @Description 4. 更新节点信息
     * @Param [no, name, nickName]
     */
    private static void updateNode(HeroNode node) {
        // 首先获取头结点
        HeroNode tempNode = headNode;
        // 遍历节点，找到要修改的节点的前一个节点
        while (true) {
            // 判断当前节点是不是最后一个节点，如果到了末尾还没有找到目标节点，报错警告
            if (tempNode.next == null) {
                System.out.println("!!!!!!!!!! 目标节点不存在！");
                break;
            }

            if (tempNode.next.getNo() == node.getNo()) {
                // 更新节点信息
                tempNode.next.setName(node.getName());
                tempNode.next.setNickName(node.getNickName());
                System.out.println("*********** 更新节点成功！");
                break;
            }
            tempNode = tempNode.next;
        }
    }

    /**
     * @Description 5. 打印链表中所有的节点
     */
    private static void showNodes() {
        // 首先获取头结点
        HeroNode tempNode = headNode;
        System.out.println("头结点：" + headNode);
        while (true) {
            if (tempNode.next == null) {
                break;
            }
            tempNode = tempNode.next;
            System.out.println(tempNode);
        }
    }

    /**
     * @Description 6. 获取链表节点个数（包含头结点）
     */
    private static void getSize(){
        // 首先获取头结点
        HeroNode tempNode = headNode;
        int length = 0;
        while (true){
            // 因为包含头结点，所以就上来就 ++。
            length++;
            if (tempNode.next == null){ // 如果到了最后一个节点
                break;
            }
            tempNode = tempNode.next;
        }
        System.out.println("节点个数为：" + length);
    }


}

